package evostar.access;

import evostar.exception.ServerException;
import evostar.model.HostHolder;
import evostar.model.User;
import evostar.result.CodeMsg;
import evostar.service.RedisService;
import evostar.service.SeckillService;
import evostar.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class TokenInterceptor implements HandlerInterceptor {
    @Autowired
    private UserService userService;
    @Autowired
    private RedisService redisService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            User user = this.getUser(request, response);
            HostHolder.setUser(user);
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            AccessToken accessToken = handlerMethod.getMethod().getAnnotation(AccessToken.class);
            if (accessToken == null) {
                return true;
            }
            if (user == null && accessToken.needLogin()) {
                response.sendRedirect("/login/");
                return false;
            }
            //限流
            int second = accessToken.seconds();
            int maxCount = accessToken.maxCount();
            if (second > 0 && maxCount > 0 && user != null) {
                String uri = request.getRequestURI();
                String key = SeckillService.ACCESS + user.getId() + "_" + uri;
                Integer count = redisService.getValue(key, Integer.class);
                if (count == null) {
                    redisService.setValue(key, 1, second);
                } else if (count < maxCount) {
                    redisService.increment(key);
                } else {
                    throw new ServerException(CodeMsg.ACCESS_TOO_MANY);
                }
            }
        }
        return true;
    }

    public User getUser(HttpServletRequest request, HttpServletResponse response) {
        String cookieToken = this.getCookieValue(request, UserService.TOKEN_NAME);
        if (StringUtils.isEmpty(cookieToken)) {
            return null;
        }
        return userService.getByToken(response, cookieToken);
    }

    public String getCookieValue(HttpServletRequest request, String cookieName) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null || cookies.length == 0) {
            return null;
        }
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(cookieName)) {
                return cookie.getValue();
            }
        }
        return null;
    }
}
